package zpe.jsf.view.bean;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

import org.springframework.util.CollectionUtils;

import zpe.genericcrud.jsf.view.bean.AbstractCrudBean;
import zpe.genericcrud.jsf.view.bean.FacesUtils;
import zpe.model.Carga;
import zpe.model.Cliente;
import zpe.model.Conteiner;
import zpe.model.ItemCarga;
import zpe.model.Lacre;
import zpe.model.NomeclaturaNCM;
import zpe.model.NomeclaturasCarga;
import zpe.model.TransportadoraCarga;
import zpe.model.enums.Acondicionamento;
import zpe.service.CargaService;

@ManagedBean(name = "cargaBean")
@ViewScoped
public class CargaBean extends AbstractCrudBean<Carga, CargaService> {

	@ManagedProperty("#{cargaService}")
	protected CargaService service;

	public Cliente transportadora;
	
	public DataModel<Cliente> transportadorasModal;
	
	public DataModel<ItemCarga> itensCargaDataModel;
	
	public DataModel<Cliente> transportadorasSelecionadas;
	
	public DataModel<NomeclaturaNCM> nomeclaturasSelecionadas;
	
	public DataModel<Lacre> lacresSelecionados;

	public DataModel<Cliente> proprietariosModal;

	public DataModel<NomeclaturaNCM> nomeclaturasModal;

	public ItemCarga itemCarga;
	
	public NomeclaturaNCM nomeclaturaNCM;
	
	public Lacre lacre;
	
	public Conteiner conteiner;

	public List<NomeclaturaNCM> nomeclaturasRemovidas;
	
	public DataModel<ItemCarga> getItensCargaDataModel() {
		return itensCargaDataModel;
	}

	public void setItensCargaDataModel(DataModel<ItemCarga> itensCargaDataModel) {
		this.itensCargaDataModel = itensCargaDataModel;
	}

	public Conteiner getConteiner() {
		return conteiner;
	}

	public void setConteiner(Conteiner conteiner) {
		this.conteiner = conteiner;
	}

	public DataModel<Lacre> getLacresSelecionados() {
		return lacresSelecionados;
	}

	public void setLacresSelecionados(DataModel<Lacre> lacresSelecionados) {
		this.lacresSelecionados = lacresSelecionados;
	}

	public Lacre getLacre() {
		return lacre;
	}

	public void setLacre(Lacre lacre) {
		this.lacre = lacre;
	}

	public DataModel<NomeclaturaNCM> getNomeclaturasSelecionadas() {
		return nomeclaturasSelecionadas;
	}

	public void setNomeclaturasSelecionadas(
			DataModel<NomeclaturaNCM> nomeclaturasSelecionadas) {
		this.nomeclaturasSelecionadas = nomeclaturasSelecionadas;
	}

	public DataModel<Cliente> getProprietariosModal() {
		return proprietariosModal;
	}

	public void setProprietariosModal(DataModel<Cliente> proprietariosModal) {
		this.proprietariosModal = proprietariosModal;
	}

	public DataModel<Cliente> getTransportadorasSelecionadas() {
		return transportadorasSelecionadas;
	}

	public void setTransportadorasSelecionadas(
			DataModel<Cliente> transportadorasSelecionadas) {
		this.transportadorasSelecionadas = transportadorasSelecionadas;
	}

	public ItemCarga getItemCarga() {
		return itemCarga;
	}

	public void setItemCarga(ItemCarga itemCarga) {
		this.itemCarga = itemCarga;
	}

	public Cliente getTransportadora() {
		return transportadora;
	}

	public void setTransportadora(Cliente transportadora) {
		this.transportadora = transportadora;
	}
	
	public DataModel<Cliente> getTransportadorasModal() {
		return transportadorasModal;
	}

	public void setTransportadorasModal(DataModel<Cliente> transportadorasModal) {
		this.transportadorasModal = transportadorasModal;
	}

	public NomeclaturaNCM getNomeclaturaNCM() {
		return nomeclaturaNCM;
	}

	public void setNomeclaturaNCM(NomeclaturaNCM nomeclaturaNCM) {
		this.nomeclaturaNCM = nomeclaturaNCM;
	}


	public DataModel<NomeclaturaNCM> getNomeclaturasModal() {
		return nomeclaturasModal;
	}

	public void setNomeclaturasModal(DataModel<NomeclaturaNCM> nomeclaturasModal) {
		this.nomeclaturasModal = nomeclaturasModal;
	}

	@PostConstruct
	public void init() {

		lacre = new Lacre();
		
		conteiner = new Conteiner();
		
		itemCarga = new ItemCarga();
		
		transportadora = new Cliente();
		
		nomeclaturaNCM = new NomeclaturaNCM();
		
		transportadorasModal = new ListDataModel<Cliente>();
		
		nomeclaturasModal = new ListDataModel<NomeclaturaNCM>();
		
		proprietariosModal = new ListDataModel<Cliente>();
		
		transportadorasSelecionadas = new ListDataModel<Cliente>( new ArrayList<Cliente>() );
		
		nomeclaturasSelecionadas = new ListDataModel<NomeclaturaNCM>( new ArrayList<NomeclaturaNCM>() );
		
		lacresSelecionados = new ListDataModel<Lacre>( new ArrayList<Lacre>() );
		
		itensCargaDataModel = new ListDataModel<ItemCarga>( new ArrayList<ItemCarga>() );
		
		nomeclaturasRemovidas = new ArrayList<NomeclaturaNCM>(0);
		
		getEntity().setItens( new ArrayList<ItemCarga>() );
		
		getEntity().setProprietario( new Cliente() );
				
	}


	
	public List<SelectItem> getAcondicionamento() {

		List<SelectItem> itens = new ArrayList<SelectItem>(0);

		for (Acondicionamento item : Acondicionamento.values())
			itens.add(new SelectItem(item, item.getDescricao()));

		return itens;

	}
	
	
	@SuppressWarnings("unchecked")
	public void addLacre() {
		
		List<Lacre> lacresSelecionados = (( List<Lacre> ) this.lacresSelecionados.getWrappedData()) ;
		
		if (lacresSelecionados.size() > 4) {
			
			FacesUtils.addWarnMessage("Número máximo de lacres já informado!");
			return;
			
		}
		
		boolean existsLacre = false;
		
		for (Lacre l : lacresSelecionados) {
			
			if(l.getDescricao().equalsIgnoreCase( this.lacre.getDescricao() )){
				
				existsLacre = true;
				
				break;
				
			}
			
		}
		
		if( !existsLacre ) {
			
			lacresSelecionados.add( lacre );
			
		}else{
			
			FacesUtils.addWarnMessage("Lacre já incluído!");
			
		}
		
		lacre = new Lacre();
		
	}

	@SuppressWarnings("unchecked")
	public void removerLacre() {
		
		List<Lacre> lacres = (List<Lacre>) this.lacresSelecionados.getWrappedData();
		
		Integer indice = lacresSelecionados.getRowIndex();
		
		if(!CollectionUtils.isEmpty( lacres )) {
			
			lacres.remove(indice.intValue() );
		}
		
	}
	
	@SuppressWarnings("unchecked")
	public void listTransportadoras(ActionEvent event){
		
		try {
			
			transportadorasModal = new ListDataModel<Cliente>();
			
			if(!"".equalsIgnoreCase(transportadora.getDescricao() )){

				List<Cliente> clientes = getService().getServiceCliente().findTransportadora(transportadora);

				if(!CollectionUtils.isEmpty(clientes)){
					
					if(clientes.size() > 1) {
						
						transportadorasModal.setWrappedData(clientes);
						
					}else{
						
						transportadora = clientes.get(0);
						
						if( !((List<Cliente>) transportadorasSelecionadas.getWrappedData()).contains(transportadora) ){
							
							List<Cliente> clientesSelecionados =  (List<Cliente>) transportadorasSelecionadas.getWrappedData() ;
							
							clientesSelecionados.add(transportadora);
							
						}else {
							
							FacesUtils.addWarnMessage("Transportadora já adicionada!");
							
						}
						
						
						transportadora = new Cliente();
						
					}
					
				}else{
					
					FacesUtils.addWarnMessage("Nenhuma transportadora encontrada!");
					
				}

			}else{
				FacesUtils.addErrorMessage("Campo de preenchimento obrigatório!");
				return;
			}
			
		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro durante a consulta!");
			
			e.printStackTrace();
			
		}
		
	}

	@SuppressWarnings("unchecked")
	public void selectTransportadora(ActionEvent event){

		this.transportadora = transportadorasModal.getRowData();
		
		List<Cliente> clientesSelecionados =  ((List<Cliente>) transportadorasSelecionadas.getWrappedData()) ;
		
		if(!clientesSelecionados.contains(this.transportadora)){
			
			clientesSelecionados.add(transportadora);
			
		}else{
			
			FacesUtils.addWarnMessage("Transportadora já adicionada!");
			
		}
		
		((List<Cliente>) transportadorasModal.getWrappedData()).clear();
		
		transportadora = new Cliente();
		
	}
	
	@SuppressWarnings("unchecked")
	public void removerTransportadora(ActionEvent event){
		
		List<Cliente> clientesSelecionados =  ((List<Cliente>) transportadorasSelecionadas.getWrappedData()) ;
		
		Cliente c = transportadorasSelecionadas.getRowData();
		
		clientesSelecionados.remove(c);
		
	}
	
	
	public void listProprietarios(ActionEvent event){
		
		try {
			
			proprietariosModal = new ListDataModel<Cliente>();
			
			Cliente cliente = getEntity().getProprietario();
			
			if(!"".equalsIgnoreCase(cliente.getCnpj()) && cliente.getCnpj() !=null ){
				
				List<Cliente> clientes = getService().getServiceCliente().findProprietario(getEntity().getProprietario());

				if(!CollectionUtils.isEmpty(clientes)){
					
					if(clientes.size() > 1) {
						
						proprietariosModal.setWrappedData(clientes);
						
					}else{
						
						getEntity().setProprietario(clientes.get(0));
						
					}
					
				}else{
					
					FacesUtils.addWarnMessage("Nenhum proprietário encontrado!");
					
				}

			}else{
				
				FacesUtils.addErrorMessage("Campo de preenchimento obrigatório!");
				
				return;
				
			}
			
			
		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro durante a consulta!");
			
			e.printStackTrace();
			
		}
		
	}

	
	@SuppressWarnings("unchecked")
	public void selectProprietario(ActionEvent event){

		getEntity().setProprietario(proprietariosModal.getRowData());
		
		((List<Cliente>) proprietariosModal.getWrappedData()).clear();
		
	}
	
	@SuppressWarnings("unchecked")
	public void removeNCM(ActionEvent event){
		
		try {
			
			NomeclaturaNCM nomeclatura = getNomeclaturasSelecionadas().getRowData();
			
			int indice = getNomeclaturasSelecionadas().getRowIndex();
			
			List<NomeclaturaNCM> lista = ((List<NomeclaturaNCM>) getNomeclaturasSelecionadas().getWrappedData());
			
			if(!CollectionUtils.isEmpty(lista)){
				
				if(nomeclatura.getId()!=null){
					
					nomeclaturasRemovidas.add(nomeclatura);

				}
				
				lista.remove(indice);
				
			}
			
			FacesUtils.addInfoMessage("Item removido com sucesso!");

		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro ao tentar remover um NCM!");
			
			e.printStackTrace();
			
		}
		
	}
	
	
	@SuppressWarnings("unchecked")
	public void listNCM(ActionEvent event){
		
		try {
			
			nomeclaturasModal = new ListDataModel<NomeclaturaNCM>();
			
			List<NomeclaturaNCM> ncms = getService().findNomeclaturas(nomeclaturaNCM);
			
			if(!CollectionUtils.isEmpty(ncms)){
				
				if(ncms.size() > 1) {
					
					nomeclaturasModal.setWrappedData(ncms);
					
				}else{
					
					nomeclaturaNCM = ncms.get(0);
					
					if( !((List<NomeclaturaNCM>) nomeclaturasSelecionadas.getWrappedData()).contains(nomeclaturaNCM) ){
						
						List<NomeclaturaNCM> ncmsSelecionadas =  (List<NomeclaturaNCM>) nomeclaturasSelecionadas.getWrappedData() ;
						
						ncmsSelecionadas.add(nomeclaturaNCM);
						
					}else {
						
						FacesUtils.addWarnMessage("NCM já adicionada!");
						
					}
					
					
					nomeclaturaNCM = new NomeclaturaNCM();
					
				}
				
			}else{
				
				FacesUtils.addWarnMessage("Nenhuma NCM encontrada!");
				
			}
			
		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro durante a consulta!");
			
			e.printStackTrace();
			
		}
		
		
	}

	@SuppressWarnings("unchecked")
	public void selectNCM(ActionEvent event){

		this.nomeclaturaNCM = nomeclaturasModal.getRowData();
		
		List<NomeclaturaNCM> ncmsSelecionados =  ((List<NomeclaturaNCM>) nomeclaturasSelecionadas.getWrappedData()) ;
		
		if(!ncmsSelecionados.contains(this.nomeclaturaNCM)){
			
			ncmsSelecionados.add(nomeclaturaNCM);
			
		}else{
			
			FacesUtils.addWarnMessage("NCM já adicionada!");
			
		}
		
		((List<NomeclaturaNCM>) nomeclaturasModal.getWrappedData()).clear();
		
		nomeclaturaNCM = new NomeclaturaNCM();
		
	}

	public void limparModalConteiner(ActionEvent event){
		
		conteiner = new Conteiner();
		
		lacresSelecionados = new ListDataModel<Lacre>( new ArrayList<Lacre>() );
	}
	
	@SuppressWarnings("unchecked")
	public void adicionarItemCarga(ActionEvent event){
		
		Double totalCubagemCarga = getEntity().getCubagem() + itemCarga.getCubagem();

		Double totalVolumeCarga =  getEntity().getVolumeTotal() + itemCarga.getVolumeTotalDeclarado();
		
		Double totalPesoCarga =  getEntity().getPesoTotal()  + itemCarga.getPesoTotalDeclarado();
		
		Integer totalQuatidadeCarga = getEntity().getQuantidadeItens() + itemCarga.getQtdeTotalDeclarado();
		
		getEntity().setCubagem(totalCubagemCarga);
		
		getEntity().setVolumeTotal(totalVolumeCarga);
		
		getEntity().setPesoTotal(totalPesoCarga);
		
		getEntity().setQuantidadeItens(totalQuatidadeCarga);
		
		conteiner.setLacres( (List<Lacre>) lacresSelecionados.getWrappedData() );
		
		itemCarga.setConteiner(conteiner);
		
		itemCarga.setCarga(getEntity());
		
		( (List<ItemCarga>) itensCargaDataModel.getWrappedData() ).add(itemCarga);
		
		if(getEntity().getItens() == null) {
			
			getEntity().setItens( new ArrayList<ItemCarga>(0) );
			
		}
		
		getEntity().getItens().add(itemCarga);
		
		itemCarga = new ItemCarga();
		
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void save(ActionEvent event) {
		
		try {
			
			List<Cliente> transportadoras = ((List<Cliente>) transportadorasSelecionadas.getWrappedData());
			
			List<NomeclaturaNCM> nomeclaturas = ((List<NomeclaturaNCM>) nomeclaturasSelecionadas.getWrappedData());
			
			List<ItemCarga> itensCarga = (List<ItemCarga>) getItensCargaDataModel().getWrappedData();
			
			if(CollectionUtils.isEmpty(nomeclaturas)) {
				
				FacesUtils.addErrorMessage("Informe pelo menos um NCM!");
				
				return;
				
			}
			
			if(getEntity().getAcondicionamento() == Acondicionamento.CONTEINER){

				if(CollectionUtils.isEmpty(itensCarga)) {
					
					FacesUtils.addErrorMessage("Informe pelo menos um Contêiner!");
					
					return;
					
				}
				
				getEntity().setItens( itensCarga );
				
			}
			
			getService().salvarCarga(getEntity(),transportadoras,nomeclaturas,nomeclaturasRemovidas); 
			
			FacesUtils.addInfoMessage("Operação realizada com sucesso!");
			
			setEntity(getNewEntityInstance());
			
			setCurrentState(STATE_SEARCH);

		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro durante o cadastro da carga!");
			
			e.printStackTrace();
		}
		
	}
	
	@Override
	public void prepareInsert(ActionEvent event) {
		
		try {

			super.prepareInsert(event);
			
			SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

			getEntity().setEntrada( sdf.parse( sdf.format( new Date() ) ) );
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
	}
	
	@Override
	public void prepareUpdate(ActionEvent event) {

		super.prepareUpdate(event);
		
		carregaDataModelTransportadora();
		
		carregaDataModelNomeclaturas();
		
		//Carrega ItensCarga
		if( getEntity().getAcondicionamento() == Acondicionamento.CONTEINER ) {
			
			
		}
	}
	
	
	
	private void carregaDataModelNomeclaturas() {

		//Carrega Nomeclaturas
		List<NomeclaturasCarga> nomeclaturas = getService().getServiceNomeclaturasCarga().findTransportadorasByCarga(getEntity());
		
		getEntity().setNomeclaturas( nomeclaturas );

		List<NomeclaturaNCM> n = new ArrayList<NomeclaturaNCM>(0);
		
		for (NomeclaturasCarga c : nomeclaturas) {
			
			n.add(c.getNomeclatura() );
			
		}
		
		setNomeclaturasSelecionadas(new ListDataModel<NomeclaturaNCM>(n));
		
	}

	private void carregaDataModelTransportadora() {
		
		//Carrega transportadoras
		List<TransportadoraCarga> transportadoras = getService().getServiceTransportadoraCarga().findTransportadorasByCarga(getEntity());
		
		getEntity().setTransportadoras( transportadoras );

		List<Cliente> clientes = new ArrayList<Cliente>(0);
		
		for (TransportadoraCarga c : transportadoras) {
			
			clientes.add(c.getCliente());
			
		}
		
		setTransportadorasSelecionadas(new ListDataModel<Cliente>(clientes));
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public void deleteAll(ActionEvent event) {
		
		try {
			
			getService().deletarCarga( ((List<Carga>) getEntities().getWrappedData()) );
			
			FacesUtils.addInfoMessage("Item(ns) removidos com sucesso!");
			
			List<Carga> itens = (List<Carga>) getResultSearch().getWrappedData(); 
			
			itens.removeAll( ((List<Carga>) getEntities().getWrappedData()) );
			
		} catch (Exception e) {
			
			FacesUtils.addErrorMessage("Ocorreu um erro ao tentar remover a carga!");
			e.printStackTrace();
		
		}
		
	}
	
	@Override
	public void find(ActionEvent event) {
		
		List<Carga> cargas = new ArrayList<Carga>(0);
		
		cargas = getService().findByFilter(Carga.class, getEntitySearch().notEmptyFields());
		
		if(CollectionUtils.isEmpty(cargas)) {
			
			FacesUtils.addWarnMessage("Nenhum registro foi encontrado!");
			
		}else{
			
			setResultSearch( new ListDataModel<Carga>(cargas) );
			
		}
		
	}
	
	public void validaTipoAcondicionamento(){
		
		if( getEntity().getAcondicionamento() == Acondicionamento.CONTEINER ){
			
			getEntity().setPesoTotal( new Double(0));
			getEntity().setQuantidadeItens(0);
			getEntity().setVolumeTotal(new Double(0));
			getEntity().setCubagem(new Double(0));
			
		}else{
			
			setItensCargaDataModel( new ListDataModel<ItemCarga>(new ArrayList<ItemCarga>(0)));
			
			
		}
		
	}
	
	@SuppressWarnings("unchecked")
	public void removerItemSelecionado(ActionEvent event){
		
		int itemSelecionado = getItensCargaDataModel().getRowIndex();
		
		List<ItemCarga> itensAdicionados = ((List<ItemCarga>) getItensCargaDataModel().getWrappedData());
		
		itensAdicionados.remove(itemSelecionado);
		
	}
	
	
}
